// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/download/save_file_resource_handler.h"

#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_number_conversions.h"
#include "content/browser/download/save_file_manager.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/io_buffer.h"
#include "net/url_request/redirect_info.h"
#include "net/url_request/url_request_status.h"

namespace content {

SaveFileResourceHandler::SaveFileResourceHandler(
    net::URLRequest* request,
    SaveItemId save_item_id,
    SavePackageId save_package_id,
    int render_process_host_id,
    int render_frame_routing_id,
    const GURL& url,
    AuthorizationState authorization_state)
    : ResourceHandler(request)
    , save_item_id_(save_item_id)
    , save_package_id_(save_package_id)
    , render_process_id_(render_process_host_id)
    , render_frame_routing_id_(render_frame_routing_id)
    , url_(url)
    , content_length_(0)
    , save_manager_(SaveFileManager::Get())
    , authorization_state_(authorization_state)
{
}

SaveFileResourceHandler::~SaveFileResourceHandler()
{
}

bool SaveFileResourceHandler::OnRequestRedirected(
    const net::RedirectInfo& redirect_info,
    ResourceResponse* response,
    bool* defer)
{
    final_url_ = redirect_info.new_url;
    return true;
}

bool SaveFileResourceHandler::OnResponseStarted(ResourceResponse* response,
    bool* defer)
{
    // |save_manager_| consumes (deletes):
    SaveFileCreateInfo* info = new SaveFileCreateInfo(
        url_, final_url_, save_item_id_, save_package_id_, render_process_id_,
        render_frame_routing_id_, GetRequestID(), content_disposition_,
        content_length_);
    BrowserThread::PostTask(
        BrowserThread::FILE, FROM_HERE,
        base::Bind(&SaveFileManager::StartSave, save_manager_, info));
    return true;
}

bool SaveFileResourceHandler::OnWillStart(const GURL& url, bool* defer)
{
    return authorization_state_ == AuthorizationState::AUTHORIZED;
}

bool SaveFileResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
    int* buf_size,
    int min_size)
{
    DCHECK_EQ(AuthorizationState::AUTHORIZED, authorization_state_);
    DCHECK(buf && buf_size);
    if (!read_buffer_.get()) {
        *buf_size = min_size < 0 ? kReadBufSize : min_size;
        read_buffer_ = new net::IOBuffer(*buf_size);
    }
    *buf = read_buffer_.get();
    return true;
}

bool SaveFileResourceHandler::OnReadCompleted(int bytes_read, bool* defer)
{
    DCHECK_EQ(AuthorizationState::AUTHORIZED, authorization_state_);
    DCHECK(read_buffer_.get());
    // We are passing ownership of this buffer to the save file manager.
    scoped_refptr<net::IOBuffer> buffer;
    read_buffer_.swap(buffer);
    BrowserThread::PostTask(
        BrowserThread::FILE, FROM_HERE,
        base::Bind(&SaveFileManager::UpdateSaveProgress, save_manager_,
            save_item_id_, base::RetainedRef(buffer), bytes_read));
    return true;
}

void SaveFileResourceHandler::OnResponseCompleted(
    const net::URLRequestStatus& status,
    bool* defer)
{
    if (authorization_state_ != AuthorizationState::AUTHORIZED)
        DCHECK(!status.is_success());

    BrowserThread::PostTask(
        BrowserThread::FILE, FROM_HERE,
        base::Bind(&SaveFileManager::SaveFinished, save_manager_, save_item_id_,
            save_package_id_,
            status.is_success() && !status.is_io_pending()));
    read_buffer_ = NULL;
}

void SaveFileResourceHandler::OnDataDownloaded(int bytes_downloaded)
{
    NOTREACHED();
}

void SaveFileResourceHandler::set_content_length(
    const std::string& content_length)
{
    base::StringToInt64(content_length, &content_length_);
}

} // namespace content
